#pragma once
#include "Socket.hpp"
#include "Tcpserver.hpp"
#include "Log.hpp"
#include <iostream>
#include <string>
#include <unordered_map>
#include <sstream>
#include "Util.hpp"
using namespace SocketModule;
using namespace LogModule;
const std::string gspace = " ";
const std::string glinespace = "\r\n";
const std::string glinesep = ": ";

const std::string webroot = "./wwwroot";
const std::string homepage = "index.html";
const std::string page_404 = "/404.html";
class HttpRequest
{
public:
    HttpRequest() {}
    ~HttpRequest() = default;
    std::string Uri() { return _uri; }
    std::string Serialize()
    {
        return std::string();
    }
    void ParseReqLine(std::string &reqline)
    {
        std::stringstream ss(reqline);
        ss >> _method >> _uri >> _version;
    }
    bool Deserialize(std::string &reqstr)
    {
        std::string reqline;
        bool res = Util::ReadOneLine(reqstr, &reqline, glinesep);
        LOG(LogLevel::DEBUG) << reqline;

        ParseReqLine(reqline);
        if (_uri == "/")
            _uri = webroot + _uri + homepage;
        else
            _uri = webroot + _uri;
        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_uri: " << _uri;
        LOG(LogLevel::DEBUG) << "_version: " << _version;

        return true;
    }

private:
    std::string _method;
    std::string _uri;
    std::string _version;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;
};
class HttpResponse
{
public:
    HttpResponse() : _blankline(glinespace)
    {
    }
    ~HttpResponse() = default;
    std::string Serialize()
    {
        std::string status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;
        std::string resp_headr;
        for (auto &header : _headers)
        {
            std::string line = header.first + glinesep + header.second + glinespace;
            resp_headr += line;
        }
        return status_line + resp_headr + _blankline + _text;
    }
    void SetTargetFile(const std::string &target)
    {
        _targetfile = target;
    }
    void SetCode(int code)
    {
        _code=code;
        switch (_code)
        {
        case 200:
        _desc="OK";
        break;
        case 404:
        _desc="NOT FOUND";
        break;
        
        default:
            break;
        }
    }
    void SetHeader(const std::string &key,const std::string &value)
    {
        auto iter=_headers.find(key);
        if(iter!=_headers.end())
        {
            return ;
        }
        _headers.insert(std::make_pair(key,value));
    }
    std::string Uri2Suffix(const std::string &targetfile)
    {
        auto pos=targetfile.rfind(".");
        if(pos=std::string ::npos)
        {
            return "text/html";
        }
        std::string suffix=targetfile.substr(pos);
        if(suffix==".html"||suffix==".htm")
        return "text/html";
        else if(suffix==".jpg")
        return "image/jpeg";
        else if(suffix=="png")
        return "image/png";
        else
        return "";
    }
    bool MakeResponse()
    {
        if(_targetfile=="./wwwroot/favicon.ico")
        {
            LOG(LogLevel::DEBUG)<<"用户请求："<<_targetfile<<"忽视它";
            return false;
        }
        int filesize=0;
        
        bool res = Util::ReadFileContent(_targetfile, &_text);
        if (!res)
        {
            _text="";
            LOG(LogLevel::WARNING)<<"client want get :"<<_targetfile<<" but not found";
            SetCode(404);
            _targetfile=webroot+page_404;
           filesize=Util::FileSize(_targetfile);
           std::string suffix=Uri2Suffix(_targetfile);
           SetHeader("Content-Type",suffix);
           SetHeader("Content-Length",std::to_string(filesize));
        }
        else
        {
            LOG(LogLevel::DEBUG)<<"读取文件："<<_targetfile;
            SetCode(200);
            filesize=Util::FileSize(_targetfile);
            std::string suffix=Uri2Suffix(_targetfile);
           SetHeader("Content-Type",suffix);
           SetHeader("Content-Length",std::to_string(filesize));
        }
        return true;
    }
    bool Deserialize()
    {
        return true;
    }

public:
    std::string _version;
    int _code;
    std::string _desc;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;
    std::string _targetfile;
};
class Http
{
public:
    Http(uint16_t port) : tsvrp(std::make_unique<TcpServer>(port))
    {
    }
    ~Http() = default;
    void HanlderHttpRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        std::string httpreqstr;
        int n = sock->Recv(&httpreqstr);
        if (n > 0)
        {
            HttpRequest req;
            req.Deserialize(httpreqstr);
            HttpResponse resp;
            resp.MakeResponse();
            if(resp.MakeResponse())
            {
            std::string response_str = resp.Serialize();
            sock->Send(response_str);
            }
        }
    //     #ifdef DEBUG
    //    // std::string httpreqstr;
    //     sock->Recv(&httpreqstr);
    //     std::cout << httpreqstr;

    //     HttpResponse resp;
    //     resp._version = "HTTP/1.1";
    //     resp._code = 200;
    //     resp._desc = "OK";

    //     std::string filename = webroot + homepage;
    //     bool res = Util::ReadFileContent(filename, &(resp._text));
    //     (void)res;
    //     std::string response_str = resp.Serialize();
    //     sock->Send(response_str);
    //    # endif
    }
    void Start()
    {
        tsvrp->Start([this](std::shared_ptr<Socket> &sock, InetAddr &client)
                     { this->HanlderHttpRequest(sock, client); });
    }

private:
    std::unique_ptr<TcpServer> tsvrp;
};